package com.bytech.common.biz.exception.handler;

import com.bytech.common.biz.entity.base.BaseResult;
import com.bytech.common.biz.entity.base.BlogResultStatus;
import com.bytech.common.biz.exception.BlogApiGlobalRuntimeException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 *
 * @author zhaolt
 * @date 2021/7/28 20:30
 */
@RestControllerAdvice
@RefreshScope
@Slf4j
public class BlogApiGlobalExceptionHandler {

    /**
     * 是否返回异常堆栈
     */
    @Value("${blog.print-stack-trace.enable:false}")
    private boolean printStackTraceEnable;

    /**
     * 独立运行在每个服务中的业务异常处理
     */
    @ExceptionHandler(value = BlogApiGlobalRuntimeException.class)
    public BaseResult<? extends RuntimeException> handleBlogException(BlogApiGlobalRuntimeException exception) {
        log.error(exception.getMessage());
        return printStackTraceEnable ? BaseResult.<BlogApiGlobalRuntimeException>error(exception).data(exception).build()
                : BaseResult.<BlogApiGlobalRuntimeException>error(exception.getMessage()).data(null).build();
    }

    /**
     * 独立运行在每个服务中处理 feign 调用异常的处理器
     */
    @ExceptionHandler(value = FeignException.class)
    public BaseResult<RuntimeException> handleFeignException(FeignException exception) {
        log.error(exception.getMessage());
        // TODO 通过 exception 携带的 request 中的 URL 确定具体调用的哪个微服务报错了，并返回相应的友好提示
        BlogResultStatus resultStatus = null;
        switch (exception.status()) {
            case 502:
                resultStatus = BlogResultStatus.REMOTE_SERVICE_BAD_GATEWAY;
                break;
            case 503:
                resultStatus = BlogResultStatus.REMOTE_SERVICE_UNAVAILABLE;
                break;
            case 504:
                resultStatus = BlogResultStatus.REMOTE_SERVICE_GATEWAY_TIMEOUT;
                break;
            default:
                resultStatus = BlogResultStatus.SERVER_ERROR;
                break;
        }
        exception.printStackTrace();
        return BaseResult.<RuntimeException>error(resultStatus).build();
    }

    /**
     * 其他未捕获的异常抛出由此处理器拦截并返回友好提示
     */
    @ExceptionHandler(value = Exception.class)
    public BaseResult<RuntimeException> handleRuntimeException(RuntimeException exception) {
        log.error("exception handler capture an unhandled exception！");
        log.error(exception.getMessage());
        return printStackTraceEnable ? BaseResult.<RuntimeException>error(exception.getMessage()).data(exception).build()
                : BaseResult.<RuntimeException>error(BlogResultStatus.SERVER_ERROR).data(null).build();
    }
}
